home *** CD-ROM | disk | FTP | other *** search
/ Programmer Plus 2007 / Programmer-Plus-2007.iso / Programming / Report Writers / Crystal Repot 9.0 Full CD version / Setup.exe / SRC / HOARDDLL.ZIP / 3rdParty / hoard / libhoard-2.0.2 / arch-specific.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-06-18  |  12.4 KB  |  520 lines

  1. ///-*-C++-*-//////////////////////////////////////////////////////////////////
  2. //
  3. // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
  4. //        for Shared-Memory Multiprocessors
  5. // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
  6. //
  7. // Copyright (c) 1998-2000, The University of Texas at Austin.
  8. //
  9. // This library is free software; you can redistribute it and/or modify
  10. // it under the terms of the GNU Library General Public License as
  11. // published by the Free Software Foundation, http://www.fsf.org.
  12. //
  13. // This library is distributed in the hope that it will be useful, but
  14. // WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. //////////////////////////////////////////////////////////////////////////////
  19.  
  20.  
  21. //////////////////////////////////////////////////////////////////////////////
  22. //
  23. // Note: This file was modified by Crystal Decisions in June 2002.
  24. //
  25. //////////////////////////////////////////////////////////////////////////////
  26.  
  27.  
  28. #include <assert.h>
  29.  
  30. #include "arch-specific.h"
  31.  
  32. #if defined(CRYSTAL_HOARD) && defined(__SVR4)
  33.   // The Solaris version of the Crystal Hoard will call malloc instead of mmap.
  34.   // This is a bit of an experiment.  mmap gets very slow when managing many
  35.   // small allocations, which we need to do if we want to release blocks.
  36.   #include <dlfcn.h>
  37. #endif
  38.  
  39. // How many iterations we spin waiting for a lock.
  40. enum { SPIN_LIMIT = 100 };
  41.  
  42. // Crystal will define this in arch-specific.h
  43. #if !defined(CRYSTAL_HOARD)
  44. // The values of a user-level lock.
  45. enum { UNLOCKED = 0, LOCKED = 1 };
  46. #endif
  47.  
  48. extern "C" {
  49.  
  50. #if defined(__BEOS__)
  51.  
  52. #include <OS.h>
  53. #include <unistd.h>
  54.  
  55. void hoardCreateThread (hoardThreadType &t,
  56.             void *( *function)( void *),
  57.             void *arg)
  58. {
  59.   t = spawn_thread((int32 (*)(void*))function, "some thread",
  60.            B_NORMAL_PRIORITY, arg);
  61.   if (t >= B_OK) resume_thread(t);
  62.   else debugger("spawn_thread() failed!");
  63. }
  64.  
  65.  
  66. void hoardJoinThread (hoardThreadType &t)
  67. {
  68.   status_t dummy;
  69.   wait_for_thread(t, &dummy);
  70. }
  71.  
  72.  
  73. void hoardSetConcurrency (int)
  74. {
  75. }
  76.  
  77.  
  78. int hoardGetThreadID (void)
  79. {
  80.   return find_thread(0);
  81. }
  82.  
  83.  
  84. void hoardLockInit (hoardLockType &lock)
  85. {
  86.   lock.ben = 0;
  87.   lock.sem = create_sem(0, "a hoard lock");
  88. }
  89.  
  90.  
  91. void hoardLock (hoardLockType &lock)
  92. {
  93.   if((atomic_add(&(lock.ben), 1)) >= 1) acquire_sem(lock.sem);
  94. }
  95.  
  96.  
  97. void hoardUnlock (hoardLockType &lock)
  98. {
  99.   if((atomic_add(&(lock.ben), -1)) > 1) release_sem(lock.sem);
  100. }
  101.  
  102. int hoardGetPageSize (void)
  103. {
  104.   return B_PAGE_SIZE;
  105. }
  106.  
  107. int hoardGetNumProcessors (void)
  108. {
  109.   system_info si;
  110.   status_t result = get_system_info(&si);
  111.   assert (result == B_OK);
  112.   return si.cpu_count;
  113. }
  114.  
  115.  
  116. void * hoardSbrk (long size)
  117. {
  118.   return sbrk(size + hoardHeap::ALIGNMENT - 1);
  119. }
  120.  
  121.  
  122. void hoardUnsbrk (void * ptr, long size)
  123. {
  124.   // NOT CURRENTLY IMPLEMENTED!
  125. }
  126.  
  127. void hoardYield (void)
  128. {
  129. }
  130.  
  131. unsigned long hoardInterlockedExchange (unsigned long * oldval,
  132.                     unsigned long newval)
  133. {
  134.   // This *should* be made atomic.  It's never used in the BeOS
  135.   // version, so this is included strictly for completeness.
  136.   unsigned long o = *oldval;
  137.   *oldval = newval;
  138.   return o;
  139. }
  140.  
  141.  
  142. #elif !defined(WIN32)   // UNIX
  143.  
  144.  
  145. #if USE_SPROC
  146. #include <sys/types.h>
  147. #include <sys/wait.h>
  148. #include <unistd.h>
  149. #include <ulocks.h>
  150. #endif
  151.  
  152. void hoardCreateThread (hoardThreadType& t,
  153.             void *(*function) (void *),
  154.             void * arg)
  155. {
  156. #if USE_SPROC
  157.   typedef void (*sprocFunction) (void *);
  158.   t = sproc ((sprocFunction) function, PR_SADDR, arg);
  159. #else
  160.   pthread_attr_t attr;
  161.   pthread_attr_init (&attr);
  162. #if defined(_AIX)
  163.   // Bound (kernel-level) threads.
  164.   pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
  165. #endif
  166.   pthread_create (&t, &attr, function, arg);
  167. #endif
  168. }
  169.  
  170. void hoardJoinThread (hoardThreadType& t)
  171. {
  172. #if USE_SPROC
  173.   waitpid (t, 0, 0);
  174. #else
  175.   pthread_join (t, NULL);
  176. #endif
  177. }
  178.  
  179. #if defined(__linux)
  180. // This extern declaration is required for Linux.
  181. extern "C" void pthread_setconcurrency (int n);
  182. #endif
  183.  
  184. void hoardSetConcurrency (int n)
  185. {
  186. #if USE_SPROC
  187.   usconfig (CONF_INITUSERS, n);
  188. #elif defined(__SVR4) // Solaris
  189.   thr_setconcurrency (n);
  190. #else
  191.   pthread_setconcurrency (n);
  192. #endif
  193. }
  194.  
  195.  
  196. #if defined(__SVR4) // Solaris
  197.  
  198. // Solaris's two-level threads model gives us an edge here;
  199. // we can hash on the LWP's id. This helps us in two ways:
  200. // (1) there are likely to be far fewer LWP's than threads,
  201. // (2) if there's a one-to-one correspondence between LWP's
  202. //     and the number of processors (usually the case), then
  203. //     the number of heaps used will be the same as the number
  204. //     of processors (the optimal case).
  205. // Here we rely on an undocumented call in libthread.so, which
  206. // turns out to be MUCH cheaper than the documented _lwp_self(). Go figure.
  207.  
  208.   #if defined(CRYSTAL_HOARD)
  209.     // Crystal will use the undocumented _lwp_self(), only if it exists
  210.     // in the process' symbol space.  Otherwise, it will use the documented
  211.     // version.  The allows us to LD_PRELOAD the Hoard into single-threaded apps.
  212.     // Not much to be gained by this, except that now you don't have to worry
  213.     // about your LD_PRELOAD so much.
  214.     #include <sys/lwp.h>
  215.     typedef unsigned int (*lwp_self_func)(void);
  216.   #endif
  217.   extern "C" unsigned int lwp_self(void);
  218. #endif
  219.  
  220. int hoardGetThreadID (void) {
  221. #if USE_SPROC
  222.   // This hairiness has the same effect as calling getpid(),
  223.   // but it's MUCH faster since it avoids making a system call
  224.   // and just accesses the sproc-local data directly.
  225.   int pid = (int) PRDA->sys_prda.prda_sys.t_pid;
  226.   return pid;
  227. #else
  228. #if defined(__linux)
  229.   // Consecutive thread id's in Linux are 1024 apart;
  230.   // dividing off the 1024 gives us an appropriate thread id.
  231.   return (int) pthread_self() >> 10; // (>> 10 = / 1024)
  232. #endif
  233. #if defined(__SVR4)
  234.  
  235.   #if defined(CRYSTAL_HOARD)
  236.   // Crystal will use the undocumented lwp_self() function only if
  237.   // it exists in the process' symbol space.
  238.   static lwp_self_func undocumented_lwp_self = (lwp_self_func)dlsym(RTLD_DEFAULT, "lwp_self");
  239.   if ( undocumented_lwp_self )
  240.     return (int)undocumented_lwp_self();
  241.   else
  242.     return (int) _lwp_self();
  243.   #else
  244.   return (int) lwp_self();
  245.   #endif
  246. #endif
  247.   return (int) pthread_self();
  248. #endif
  249. }
  250.  
  251.  
  252. // If we are using either Intel or SPARC,
  253. // we use our own lock implementation
  254. // (spin then yield). This is much cheaper than
  255. // the ordinary mutex, at least on Linux and Solaris.
  256.  
  257. #if USER_LOCKS && (defined(i386) || defined(sparc) || defined(__sgi) || defined(ppc))
  258.  
  259. #include <sched.h>
  260.  
  261. #if defined(__sgi)
  262. #include <mutex.h>
  263. #endif
  264.  
  265.  
  266. // Atomically:
  267. //   retval = *oldval;
  268. //   *oldval = newval;
  269. //   return retval;
  270.  
  271. #if defined(sparc) && !defined(__GNUC__)
  272. extern "C" unsigned long InterlockedExchange (unsigned long * oldval,
  273.                           unsigned long newval);
  274. #else
  275. static inline unsigned long InterlockedExchange (unsigned long * oldval,
  276.                          unsigned long newval)
  277. {
  278. #if defined(sparc)
  279.   asm volatile ("swap [%1],%0"
  280.         :"=r" (newval)
  281.         :"r" (oldval), "0" (newval)
  282.         : "memory");
  283.  
  284. #endif
  285. #if defined(i386)
  286.   asm volatile ("xchgl %0, %1"
  287.         : "=r" (newval)
  288.         : "m" (*oldval), "0" (newval)
  289.         : "memory");
  290. #endif
  291. #if defined(__sgi)
  292.   newval = test_and_set (oldval, newval);
  293. #endif
  294. #if defined(ppc)
  295.   int ret;
  296.   asm volatile ("sync;"
  297.         "0:    lwarx %0,0,%1 ;"
  298.         "      xor. %0,%3,%0;"
  299.         "      bne 1f;"
  300.         "      stwcx. %2,0,%1;"
  301.         "      bne- 0b;"
  302.         "1:    sync"
  303.     : "=&r"(ret)
  304.     : "r"(oldval), "r"(newval), "r"(*oldval)
  305.     : "cr0", "memory");
  306. #endif
  307.   return newval;
  308. }
  309. #endif
  310.  
  311. unsigned long hoardInterlockedExchange (unsigned long * oldval,
  312.                     unsigned long newval)
  313. {
  314.   return InterlockedExchange (oldval, newval);
  315. }
  316.  
  317. void hoardLockInit (hoardLockType& mutex) {
  318.   InterlockedExchange (&mutex, UNLOCKED);
  319. }
  320.  
  321. #include <stdio.h>
  322.  
  323. void hoardLock (hoardLockType& mutex) {
  324.   // A yielding lock (with an initial spin).
  325.   int i;
  326.   while (1) {
  327.     i = 0;
  328.     while (i < SPIN_LIMIT) {
  329.       if (InterlockedExchange (&mutex, LOCKED) == UNLOCKED) {
  330.         // We got the lock.
  331.         return;
  332.       }
  333.       i++;
  334.     }
  335.     // The lock is still being held by someone else.
  336.     // Give up our quantum.
  337.     hoardYield();
  338.   }
  339. }
  340.  
  341. void hoardUnlock (hoardLockType& mutex) {
  342.   InterlockedExchange (&mutex, UNLOCKED);
  343. }
  344.  
  345. #else
  346.  
  347. // use non-user-level locks. 
  348.  
  349. #endif // USER_LOCKS
  350.  
  351. #if defined(__SVR4)
  352. #include <thread.h>
  353. #endif
  354.  
  355. void hoardYield (void)
  356. {
  357. #if defined(__SVR4)
  358.   thr_yield();
  359. #else
  360.   sched_yield();
  361. #endif
  362. }
  363.  
  364. #if 1 // !(defined(__sgi))
  365. #include <sys/types.h>
  366. #include <sys/stat.h>
  367. #include <fcntl.h>
  368. #include <unistd.h>
  369. #include <sys/mman.h>
  370. #endif
  371.  
  372.  
  373. #if defined(CRYSTAL_HOARD) && defined(__SVR4)
  374. void * hoardSbrk (long size)
  375. {
  376.   // Try to grab the next nearest "malloc".  This trick will allow other memory allocators to be
  377.   // super-imposed with us.  If we're not sitting on any other memory allocators, this will pick
  378.   // up the libc.so.1 malloc.  If THAT fails, we'll use mmap.
  379.   typedef void * (*mallocFunc)(size_t size);
  380.   static mallocFunc libc_malloc = (mallocFunc)dlsym(RTLD_NEXT, "malloc");
  381.  
  382.   if ( libc_malloc )
  383.     return libc_malloc(size);
  384.   else
  385.   {
  386.     // Use mmap to get memory from the backing store.
  387.     static int fd = ::open ("/dev/zero", O_RDWR);
  388.     char * ptr = (char *) mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
  389.     if (ptr == (char *) MAP_FAILED)
  390.       return NULL;
  391.     else
  392.       return ptr;
  393.   }
  394. }
  395.  
  396. void hoardUnsbrk (void * ptr, long size)
  397. {
  398.   // Try to grab the next nearest "free".  This trick will allow other memory allocators to be
  399.   // super-imposed with us.  If we're not sitting on any other memory allocators, this will pick
  400.   // up the libc.so.1 free.  If THAT fails, we'll use munmap.
  401.   typedef void (*freeFunc)(void * ptr);
  402.   static freeFunc libc_free = (freeFunc)dlsym(RTLD_NEXT, "free");
  403.  
  404.   if ( libc_free )
  405.     libc_free(ptr);
  406.   else
  407.   {
  408.     int result = munmap ((char *) ptr, size);
  409.     assert(result == 0);
  410.   }
  411. }
  412.  
  413. #else  // CRYSTAL_HOARD && __SVR4
  414.  
  415. void * hoardSbrk (long size) {
  416. #if defined(linux)
  417. #if USER_LOCKS
  418.   static hoardLockType sbrkLock = 0;
  419. #else
  420.   static hoardLockType sbrkLock = PTHREAD_MUTEX_INITIALIZER;
  421. #endif
  422. #endif
  423.   // Use mmap to get memory from the backing store.
  424.   static int fd = ::open ("/dev/zero", O_RDWR);
  425. #if defined(linux)
  426.   hoardLock (sbrkLock);
  427. #endif
  428.   char * ptr = (char *) mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
  429.   char * retPtr;
  430.   if (ptr == (char *) MAP_FAILED) {
  431.     retPtr = NULL;
  432.   } else {
  433.     retPtr = ptr;
  434.   }
  435. #if defined(linux)
  436.   hoardUnlock (sbrkLock);
  437. #endif
  438.   return retPtr;
  439. }
  440.  
  441. void hoardUnsbrk (void * ptr, long size)
  442. {
  443. #if defined(linux)
  444. #if USER_LOCKS
  445.   static hoardLockType sbrkLock = 0;
  446. #else
  447.   static hoardLockType sbrkLock = PTHREAD_MUTEX_INITIALIZER;
  448. #endif
  449. #endif
  450. #if defined(linux)
  451.   hoardLock (sbrkLock);
  452. #endif
  453.   int result = munmap ((char *) ptr, size);
  454.   assert (result == 0);
  455. #if defined(linux)
  456.   hoardUnlock (sbrkLock);
  457. #endif
  458. }
  459.  
  460. #endif // CRYSTAL_HOARD && __SVR4
  461.  
  462. int hoardGetPageSize (void)
  463. {
  464.   return (int) sysconf(_SC_PAGESIZE);
  465. }
  466.  
  467.  
  468. #if defined(linux)
  469. #include <sys/types.h>
  470. #include <sys/stat.h>
  471. #include <fcntl.h>
  472. #include <string.h>
  473. #endif
  474.  
  475. #if defined(__sgi)
  476. #include <sys/types.h>
  477. #include <sys/sysmp.h>
  478. #include <sys/sysinfo.h>
  479. #endif
  480.  
  481. int hoardGetNumProcessors (void)
  482. {
  483. #if !(defined(linux))
  484. #if defined(__sgi)
  485.   return (int) sysmp(MP_NAPROCS);
  486. #else
  487.   return (int) sysconf(_SC_NPROCESSORS_ONLN);
  488. #endif
  489. #else
  490.   // Ugly workaround.  Linux's sysconf indirectly calls malloc() (at
  491.   // least on multiprocessors).  So we just read the info from the
  492.   // proc file ourselves and count the occurrences of the word
  493.   // "processor".
  494.  
  495.   // We only parse the first 32K of the CPU file.  By my estimates,
  496.   // that should be more than enough for at least 64 processors.
  497.   enum { MAX_PROCFILE_SIZE = 32768 };
  498.   char line[MAX_PROCFILE_SIZE];
  499.   int numProcessors = 0;
  500.   int fd = open ("/proc/cpuinfo", O_RDONLY);
  501.   assert (fd);
  502.   read(fd, line, MAX_PROCFILE_SIZE);
  503.   char * str = line;
  504.   while (str) {
  505.     str = strstr(str, "processor");
  506.     if (str) {
  507.       numProcessors++;
  508.       str++;
  509.     }
  510.   }
  511.   close (fd);
  512.   assert (numProcessors > 0);
  513.   return numProcessors;
  514. #endif
  515. }
  516.  
  517. #endif // UNIX
  518.  
  519. }
  520.